﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "RadiusTemporaryDimensionHandler.h"
#include "IActionManager.h"
#include "Vector3dUtils.h"
#include "TemporaryDimensionCommonsUtils.h"
#include "IGraphicsLine.h"
#include "IGraphicsNodeGroup.h"

#include "IUiDocumentViewManager.h"

#include "IUiView.h"
#include "IModelView.h"
#include "IAction.h"

#include "UiViewUtils.h"
#include "TemporaryDimensionContext.h"

#include <QLineEdit>
#include <QIntValidator>
#include <QKeyEvent>

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;



RadiusTemporaryDimensionHandler::RadiusTemporaryDimensionHandler(gcmp::IUiView* pUIView)
    : TemporaryDimensionHandler(pUIView)
    , m_isArcFillet(false)
{
}

RadiusTemporaryDimensionHandler::~RadiusTemporaryDimensionHandler(void)
{
}

bool RadiusTemporaryDimensionHandler::event(QEvent* pEvent)
{
    // 此方法应为入口键盘事件的处理函数
    if (pEvent->type() != QEvent::KeyPress)
    {
        return QObject::event(pEvent);
    }

    QKeyEvent* pKeyEvent = dynamic_cast<QKeyEvent*>(pEvent);
    DBG_WARN_AND_RETURN_UNLESS(pKeyEvent != nullptr, QObject::event(pEvent), L"难道pEvent不是键盘事件?",L"GDMPLab",L"2024-03-30");

    // 视图输入的入口
    // 当前Action启用了绘制助手时, 输入数字，激活视图内输入
    // 仅负责启动状态, 不负责状态启动后的事件处理
    if (IsInInputState() == false)
    {
        switch (pKeyEvent->key())
        {
        // 半径输入：
        case Qt::Key_0:
        case Qt::Key_1:
        case Qt::Key_2:
        case Qt::Key_3:
        case Qt::Key_4:
        case Qt::Key_5:
        case Qt::Key_6:
        case Qt::Key_7:
        case Qt::Key_8:
        case Qt::Key_9:
            ShowInputWidget(InputState::Radius, false, true, QString::number(pKeyEvent->key() - Qt::Key_0).toStdWString());
            return m_pEditor->event(pEvent);

        case VK_NUMPAD0:
        case VK_NUMPAD1:
        case VK_NUMPAD2:
        case VK_NUMPAD3:
        case VK_NUMPAD4:
        case VK_NUMPAD5:
        case VK_NUMPAD6:
        case VK_NUMPAD7:
        case VK_NUMPAD8:
        case VK_NUMPAD9:
            ShowInputWidget(InputState::Radius, false, true, QString::number(pKeyEvent->key() - VK_NUMPAD0).toStdWString());
            return m_pEditor->event(pEvent);

        default:
            break;
        }
        IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
        IActionManager::RefreshViewInput(pUIView);
    }
    return QObject::event(pEvent);
}

bool RadiusTemporaryDimensionHandler::eventFilter(QObject* obj, QEvent* pEvent)
{
    if (pEvent->type() == QEvent::KeyPress)
    {
        QKeyEvent* key_event = dynamic_cast<QKeyEvent*>(pEvent);
        if (key_event)
        {
            IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
            QWidget* pViewWidget = QWidget::find((WId)pUIView->GetUiViewId());
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pViewWidget != nullptr, L"pViewWidget指针不能为空",L"GDMPLab",L"2024-03-30");

            switch (key_event->key())
            {

            case Qt::Key_Return:
            case Qt::Key_Enter:
            case Qt::Key_Space:
            {
                OnEditorReturnPressed();
                return false;
            }

            case Qt::Key_Escape:
                HideInputWidget();
                return dynamic_cast<QObject*>(pViewWidget)->event(pEvent);

            default:
                break;
            }
        }
    }
    else if (pEvent->type() == QEvent::KeyRelease)
    {
        return true;
    }

    return QObject::eventFilter(obj, pEvent);
}

gcmp::OwnerPtr<gcmp::IGraphicsNodeGroup> RadiusTemporaryDimensionHandler::GenerateGraphics(const gcmp::ITemporaryDimensionContext* pCtx)
{
    OwnerPtr<IGraphicsNodeGroup> opGrepGroup = IGraphicsNodeGroup::Create();
    opGrepGroup->SetIsSnappable(false);

    DBG_WARN_AND_RETURN_UNLESS(pCtx, opGrepGroup, L"pCtx为空",L"GDMPLab",L"2024-03-30");
    const RadiusTemporaryDimensionContext* pRadiusCtx = dynamic_cast<const RadiusTemporaryDimensionContext*>(pCtx);
    DBG_WARN_AND_RETURN_UNLESS(pRadiusCtx, opGrepGroup, L"pRadiusCtx为空",L"GDMPLab",L"2024-03-30");

    Vector3d firstDockPos = pRadiusCtx->GetStartPt();
    Vector3d secondDockPos = pRadiusCtx->GetEndPt();
    Vector3d thirdDockPos = pRadiusCtx->GetRefPt();
    Coordinate3d coord = pRadiusCtx->GetCoord();
    m_TmpDimStyle.LengthPrecision = pRadiusCtx->GetLengthPrecision();
    m_TmpDimStyle.AnglePrecision = pRadiusCtx->GetAnglePrecision();
    m_TmpDimStyle.RadiusPrecision = pRadiusCtx->GetRadiusPrecision();

    UpdateUiView();
    IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
    IModelView* pModelView = pUIView->GetModelView();
    DBG_WARN_AND_RETURN_UNLESS(pModelView, opGrepGroup, L"pModelView为空！",L"GDMPLab",L"2024-03-30");

    double pixelLength = UiViewUtility::ComputeWorldWidthFromPixel(pUIView, 1);

    OwnerPtr<IGraphicsNodeGroup> opLengthDimensions = TemporaryDimensionCommonsUtils::GenerateRadiusDimensionFor3PtArc(
        firstDockPos, secondDockPos, thirdDockPos, coord,
        m_InputState, m_TmpDimStyle, pixelLength, m_TmpDimData);
    opGrepGroup->AddChild(TransferOwnership(opLengthDimensions));

    if (IsArcFillet())
    {
        return opGrepGroup;
    }

    gcmp::OwnerPtr<gcmp::IGraphicsLine> opLine12 = gcmp::IGraphicsLine::Create(firstDockPos, secondDockPos);
    gcmp::OwnerPtr<gcmp::IGraphicsLine> opLine13 = gcmp::IGraphicsLine::Create(firstDockPos, thirdDockPos);
    DBG_WARN_AND_RETURN_UNLESS(opLine12 && opLine13, opGrepGroup, L"创建IGraphicsLine失败",L"GDMPLab",L"2024-03-30");
    if (!(Vector3dUtils::IsEqual(firstDockPos, thirdDockPos)
        || Vector3dUtils::IsEqual(secondDockPos, thirdDockPos)
        || Vector3dUtils::IsEqual(firstDockPos, secondDockPos)
        || opLine12->IsParallel(*opLine13.get())))
    {
        OwnerPtr<IGraphicsNodeGroup> opCentralAngleDimensions = TemporaryDimensionCommonsUtils::GenerateCentralAngleDimensionFor3PtArc(
            firstDockPos, secondDockPos, thirdDockPos, coord,
            m_InputState, m_TmpDimStyle, pixelLength, m_TmpDimData);
        opGrepGroup->AddChild(TransferOwnership(opCentralAngleDimensions));
    }


    return opGrepGroup;
}

void RadiusTemporaryDimensionHandler::ShowInputWidget(InputState InputState, bool isTabShift /*= false*/, bool isOverrideValue /*= false*/, std::wstring inputValue/* = L""*/)
{
    bool isInputStateValid = (InputState == InputState::Radius);
    DBG_WARN_AND_RETURN_VOID_UNLESS(isInputStateValid, L"InputState输入非法!",L"GDMPLab",L"2024-03-30");

    m_InputState = InputState;

    if (m_InputState != InputState::None)
    {
        // 创建输入框
        if (!isTabShift)
        {
            CreateEditorWidget();
        }

        // 设置文本框过滤器
        QDoubleValidator* pRadInputValidator = NEW_AS_QT_CHILD(QDoubleValidator, this);
        pRadInputValidator->setBottom(Constants::DOUBLE_EPS); // 半径输入值不能是负数
        m_pEditor->setValidator(pRadInputValidator);
        m_pEditor->setText(QString::fromStdWString(inputValue));

        // 设置输入框位置
        SetEditorPosition(m_TmpDimData.RadiusDimensionPosition);

        // 输入合法性检查
        {
            std::unordered_map<const QLineEdit*, const ValidatorBase*> validators;
            validators.insert(std::make_pair(m_pEditor, &m_lenValidator));
            m_opValidateHelper->SetValidators(validators);
        }

        // 显示输入框
        m_pEditor->show();
        m_pEditor->setFocus();

        // 刷新当前视图
        IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
        IActionManager::RefreshViewInput(pUIView);
    }
}

bool RadiusTemporaryDimensionHandler::WakeOn(int nKeyChar, bool isCtrlPressed /*= false*/, bool isAltPressed /*= false*/, bool isShiftPressed /*= false*/)
{
    // 如果不是数字, 不处理
    if ((nKeyChar < Qt::Key_0 || nKeyChar > Qt::Key_9)
        && (nKeyChar < VK_NUMPAD0 || nKeyChar > VK_NUMPAD9)
        /*&& (nKeyChar != VK_OEM_COMMA)*/)
    {
        return false;
    }

    Qt::Key key = (Qt::Key)nKeyChar;
    Qt::KeyboardModifiers modifiers = Qt::NoModifier;
    if (isCtrlPressed)
    {
        modifiers |= Qt::ControlModifier;
    }
    if (isAltPressed)
    {
        modifiers |= Qt::AltModifier;
    }
    if (isShiftPressed)
    {
        modifiers |= Qt::ShiftModifier;
    }

    QKeyEvent keyEvent(QEvent::KeyPress, key, modifiers);
    return event(&keyEvent);
}

bool gcmp::RadiusTemporaryDimensionHandler::UpdateConfig(const ITemporaryDimensionContext * pCtx)
{
    if (!this->TemporaryDimensionHandler::UpdateConfig(pCtx))
    {
        return false;
    }

    const RadiusTemporaryDimensionContext* pRadiusCtx = dynamic_cast<const RadiusTemporaryDimensionContext*>(pCtx);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pRadiusCtx, L"pRadiusCtx为空。",L"GDMPLab",L"2024-03-30");
    this->SetArcFillet(pRadiusCtx->IsArcFilletEnabled());

    return true;
}

void RadiusTemporaryDimensionHandler::OnEditorReturnPressed()
{
    if (!IsInInputState())
    {
        return;
    }
    
    ActionViewInput inputParam;
    if (m_InputState == InputState::Radius)
    {
        QString radValue = m_pEditor->text();
        double radDigit = radValue.toDouble();
        inputParam.InputType = (IsArcFillet() ? ActionViewInputType::Confirm_Fillet : ActionViewInputType::Confirm_Radius);
        inputParam.InputVal = radDigit;
    }
    else
    {
        DBG_WARN(L"m_InputState怎么不是IS_Radius?",L"GDMPLab",L"2024-03-30");
    }

    // 忽略非法输入
    if (!m_lenValidator.ValidateValue(inputParam.InputVal))
    {
        m_pEditor->selectAll();
        return;
    }

    UpdateUiView();
    HideInputWidget();

    // 这个方法会结束当前的IPickPointAction!! 连带结束当前Helper的生命周期!!! 后续不应该再添加任何代码!
    IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
    IActionManager::ProcessViewInput(pUIView, inputParam);
}
